package ua.pp.bizon.cripto.spring;

import java.awt.HeadlessException;
import java.io.IOException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.Lifecycle;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import ua.pp.bizon.cripto.configuration.ConfigurationFactory;

public class SpringSupport {

    private ConfigurableApplicationContext shared;
    private ConfigurableApplicationContext context;

    public SpringSupport() {
        this.shared = getSingletonContext();
    }

    public SpringSupport(Class<?> klass, String path) {
        this(getClassRelativePath(klass, path), false);
    }

    public SpringSupport(Class<?> klass, String path, boolean includeGlobal) {
        this(getClassRelativePath(klass, path), includeGlobal);
    }

    public SpringSupport(String path, boolean includeGlobal) {
        if (includeGlobal)
            this.shared = getSingletonContext();

        this.context = new ClassPathXmlApplicationContext(new String[] { path, "ua/pp/bizon/cripto/spring/configurator.xml" }, this.shared);
    }

    protected static String getClassRelativePath(Class<?> klass, String path) {
        return klass.getPackage().getName().replace('.', '/').concat("/").concat(path);
    }

    public Object getBean(String name) {
        return getContext().getBean(name);
    }

    public <T> T getBean(String name, Class<T> klass) {
        return (T) getContext().getBean(name, klass);
    }

    public ApplicationContext getContext() {
        if (this.shared == null && this.context == null)
            throw new IllegalStateException("already closed");
        return this.context != null ? this.context : this.shared;
    }

    public void close() {
        if (this.context != null) {
            this.context.close();
            this.context = null;
        }

        if (this.shared != null) {
            releaseSingletonContext();
            this.shared = null;
        }
    }

    private static ConfigurableApplicationContext singletonContext;
    private static int referenceCount = 0;

    private static synchronized ConfigurableApplicationContext getSingletonContext() {
        if (singletonContext == null)
            singletonContext = new ClassPathXmlApplicationContext("classpath*:ua/pp/bizon/cripto/spring/*.xml");
        if (!singletonContext.isActive())
            singletonContext.refresh();
        ++referenceCount;
        return singletonContext;
    }

    private static synchronized void releaseSingletonContext() {
        if (--referenceCount == 0) {
            singletonContext.close();
            singletonContext = null;
        }
    }

    public static void main(String[] args) throws IOException {
        SpringSupport support = new SpringSupport();
        Lifecycle lifecycle = null;

        support.getBean("ConfigurationContext", ConfigurationFactory.class).configure(args);
        lifecycle = support.getBean("LifeCycle", Lifecycle.class);

        lifecycle.start();
        lifecycle.stop();
    }

}
